1 Análise Fatorial: Dados do ENEM 2020

1.2 Bibliotecas

library(tidyverse)
library(kableExtra)
library(knitr)
library(tictoc)
library(reshape2)
library(PerformanceAnalytics)
library(psych)
library(ggrepel)
library(plotly)
library(factoextra)

1.3 Loading Data

Carregando o dataset de Microdados do Enem de 2020 Dataset: ENEM2020

ENEM2020 <- read_delim("MICRODADOS_ENEM_2020.csv", delim = ";")

1.4 Cleaning Data

1.4.1 Selecionando apenas dados do estado de RR - para efeitos do estudo inicial

Selecionando apenas o Estado de RR (menos dados) Considerando o Estado da prova dos alunos participantes (e não a escola do aluno, posto que 4.878.540 participantes não indicaram a UF da Escola), e assumindo que os alunos fizeram a prova no mesmo Estado que estudam.

ENEM2020[ENEM2020$SG_UF_PROVA == 'RR', ] -> ENEM

1.4.2 Removendo as entradas dos participantes que faltaram alguma das provas

ENEM[ENEM$TP_PRESENCA_CN == '1' & 
     ENEM$TP_PRESENCA_CH == '1' & 
     ENEM$TP_PRESENCA_LC == '1' & 
     ENEM$TP_PRESENCA_MT == '1', ] -> ENEM

1.4.3 Removendo as colunas listadas acima como não necessárias para o estudo

ENEM <- select(ENEM, -c(TP_ENSINO, 
                        CO_MUNICIPIO_ESC, 
                        NO_MUNICIPIO_ESC, 
                        CO_UF_ESC,
                        SG_UF_ESC,
                        TP_DEPENDENCIA_ADM_ESC,
                        TP_LOCALIZACAO_ESC,
                        TP_SIT_FUNC_ESC,
                        TP_PRESENCA_CN,
                        TP_PRESENCA_CH,
                        TP_PRESENCA_LC,
                        TP_PRESENCA_MT,
                        NU_ANO,
                        CO_MUNICIPIO_PROVA,
                        NO_MUNICIPIO_PROVA,
                        CO_UF_PROVA,
                        CO_PROVA_CN,
                        CO_PROVA_CH,
                        CO_PROVA_LC,
                        CO_PROVA_MT,
                        TX_RESPOSTAS_CN,
                        TX_RESPOSTAS_CH,
                        TX_RESPOSTAS_LC,
                        TX_RESPOSTAS_MT,
                        TX_GABARITO_CN,
                        TX_GABARITO_CH,
                        TX_GABARITO_LC,
                        TX_GABARITO_MT))

1.4.4 Verificando NAs no dataset

colSums(is.na(ENEM))
##      NU_INSCRICAO   TP_FAIXA_ETARIA           TP_SEXO   TP_ESTADO_CIVIL 
##                 0                 0                 0                 0 
##       TP_COR_RACA  TP_NACIONALIDADE   TP_ST_CONCLUSAO   TP_ANO_CONCLUIU 
##                 0                 0                 0                 0 
##         TP_ESCOLA      IN_TREINEIRO       SG_UF_PROVA        NU_NOTA_CN 
##                 0                 0                 0                 0 
##        NU_NOTA_CH        NU_NOTA_LC        NU_NOTA_MT         TP_LINGUA 
##                 0                 0                 0                 0 
## TP_STATUS_REDACAO     NU_NOTA_COMP1     NU_NOTA_COMP2     NU_NOTA_COMP3 
##                 0                 0                 0                 0 
##     NU_NOTA_COMP4     NU_NOTA_COMP5   NU_NOTA_REDACAO              Q001 
##                 0                 0                 0                14 
##              Q002              Q003              Q004              Q005 
##                14                14                14                14 
##              Q006              Q007              Q008              Q009 
##                14                14                14                14 
##              Q010              Q011              Q012              Q013 
##                14                14                14                14 
##              Q014              Q015              Q016              Q017 
##                14                14                14                14 
##              Q018              Q019              Q020              Q021 
##                14                14                14                14 
##              Q022              Q023              Q024              Q025 
##                14                14                14                14

1.4.5 Removendo NAs:

ENEM <- na.omit(ENEM)

1.4.6 Verificando notas zero em alguma prova / participante

count(ENEM[ENEM$NU_NOTA_CN == 0.0 |
     ENEM$NU_NOTA_CH == 0.0 |
     ENEM$NU_NOTA_LC == 0.0 |
     ENEM$NU_NOTA_MT == 0.0 |
     ENEM$NU_NOTA_REDACAO == 0.0  ,]) -> zero_provas

204 participantes zeraram em alguma prova.

Alunos que zeraram nas Provas Objetivas:

14 participantes zeraram em Provas Objetivas:
- Ciências da Natureza
- Ciências Humanas
- Linguagens e Códigos
- Matemática

Apesar de várias informações publicadas na internet (como o Guia da Carreira, na publicação disponível no link: https://www.guiadacarreira.com.br/educacao/motivos-para-zerar-o-enem/) dizerem que “não dá para tirar zero nas provas objetivas do ENEM”, há 14 entradas com participantes que zeraram em alguma das 4 provas objetivas (Ciências da Natureza, Ciências Humanas, Linguagens e Códigos e Matemática)

Estas entradas, durante a análise, se comportariam como outliers, afetando os resultados. Portanto, ara efeito desta análise, estas entradas serão descartadas.

Alunos que zeraram na Redação:

193 participantes zeraram na Redação.

De acordo com o artigo publicado pelo Mundo Vestibular em 10/outubro/2022 (disponível em https://www.mundovestibular.com.br/blog/7-motivos-para-tirar-zero-na-redacao-do-enem), “Zerar na redação do Exame Nacional do Ensino Médio (Enem) pode deixar você de fora da disputa por uma bolsa de estudos em faculdade particular ou vaga na universidade pública e impedir a contratação de financiamento estudantil.”.

Considerando este fato, e os motivos que levam ao “zero”, assume-se que nenhum estudante deseja zerar na redação.

Para efeito desta análise, estas entradas serão descartadas.

1.4.7 Removendo alunos que zeraram em alguma prova

ENEM[ENEM$NU_NOTA_CN != 0.0 & 
     ENEM$NU_NOTA_CH != 0.0 &
     ENEM$NU_NOTA_LC != 0.0 &
     ENEM$NU_NOTA_MT != 0.0 &
     ENEM$NU_NOTA_REDACAO != 0.0  ,] -> ENEM

1.5 Análise Fatorial

1.5.1 Avaliando o uso de PCA

Construção da matriz de correlações (rho_ENEM) e avaliar: a) a estatística Kaiser-Meyer-Olkin (KMO); b) o alpha de Cronbach; e c) o teste de esfericidade de Bartlett.

1.5.1.1 Matriz de Correlações

rho_ENEM <- cor(ENEM[ ,c(12, 13, 14, 15, 23)])
# Colunas
# 12 - NU_NOTA_CN
# 13 - NU_NOTA_CH
# 14 - NU_NOTA_LC
# 15 - NU_NOTA_MC
# 23 - NU_NOTA_REDACAO

Observando as correlações entre variáveis

chart.Correlation(ENEM[ ,c(12, 13, 14, 15, 23)])

Mapa de calor das correlações

rho_ENEM %>% 
  melt() %>% 
  ggplot() +
  geom_tile(aes(x = Var1, y = Var2, fill = value)) +
  geom_text(aes(x = Var1, y = Var2, label = round(x = value, digits = 3)),
            size = 4) +
  labs(x = NULL,
       y = NULL,
       fill = "Correlações") +
  scale_fill_gradient2(low = "dodgerblue4", 
                       mid = "white", 
                       high = "brown4",
                       midpoint = 0) +
  theme(panel.background = element_rect("white"),
        panel.grid = element_line("grey95"),
        panel.border = element_rect(NA),
        legend.position = "bottom",
        axis.text.x = element_text(angle = 90))

1.5.1.2 Estatística KMO

KMO(r = rho_ENEM)
## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = rho_ENEM)
## Overall MSA =  0.86
## MSA for each item = 
##      NU_NOTA_CN      NU_NOTA_CH      NU_NOTA_LC      NU_NOTA_MT NU_NOTA_REDACAO 
##            0.85            0.83            0.85            0.87            0.92

1.5.1.3 Teste de Esfericidade de Bartlett

cortest.bartlett(R = rho_ENEM)
## $chisq
## [1] 217.4271
## 
## $p.value
## [1] 0.00000000000000000000000000000000000000003692827
## 
## $df
## [1] 10

p.value = 0 < 0.05

1.5.2 Análise PCA - Principal Component Analysis

1.5.2.1 Padronização da base de dados

procedimento zscores, utilizando a função scale()

1.5.2.2 Rodando a PCA

afpc_ENEM <- prcomp(ENEM_std)

1.5.2.3 Definição dos Fatores

1.5.2.3.1 Extração dos eigenvalues da Matriz de Correlações
eigenvalues_rho_ENEM <- eigen(rho_ENEM)
cat("eigenvalues: ", eigenvalues_rho_ENEM$values)
## eigenvalues:  3.233643 0.6348163 0.4652658 0.3642741 0.302001
1.5.2.3.2 Scores Fatoriais
scores_fatoriais <- t(afpc_ENEM$rotation)/afpc_ENEM$sdev 
colnames(scores_fatoriais) <- colnames(ENEM_std)

#scores_fatoriais

scores_fatoriais %>%
  t() %>%
  data.frame() %>%
  rename(PC1 = 1) %>%
  select(PC1) %>%
  kable() %>%
  kable_styling(bootstrap_options = "striped", 
                full_width = T, 
                font_size = 12)
PC1
NU_NOTA_CN 0.2602015
NU_NOTA_CH 0.2646465
NU_NOTA_LC 0.2537182
NU_NOTA_MT 0.2520155
NU_NOTA_REDACAO 0.2088575
1.5.2.3.3 Fatores

1.5.2.4 Peso das Variáveis em cada Componente Principal

data.frame(afpc_ENEM$rotation) %>%
  mutate(var = names(ENEM[c(12,13,14,15,23)]))  %>% 
  melt(id.vars = "var") %>%
  mutate(var = factor(var)) %>%
  ggplot(aes(x = var, y = value, fill = var)) +
  geom_bar(stat = "identity", color = "black") +
  facet_wrap(~variable) +
  labs(x = NULL, y = NULL, fill = "Legenda:") +
  scale_fill_viridis_d() +
  theme(panel.background = element_rect("white"),
        panel.grid = element_line("grey95"),
        panel.border = element_rect(NA),
        axis.text.x = element_text(angle = 90))

1.5.2.5 Compartilhamento das Variâncias Compartilhadas entre os Componentes Principais

ggplotly(
  fviz_eig(X = afpc_ENEM,
           ggtheme = theme_bw(), 
           barcolor = "black", 
           barfill = "dodgerblue4",
           linecolor = "darkgoldenrod3",
           main = "Compartilhamento das Variâncias Compartilhadas entre os Componentes Principais")
)

1.5.2.6 Cargas Fatoriais

k <- sum((afpc_ENEM$sdev ^ 2) > 1) #número de variáveis presentes na base de dados
cargas_fatoriais <- afpc_ENEM$rotation[, 1:k] %*% diag(afpc_ENEM$sdev[1:k])

cat("cargas fatoriais: ", cargas_fatoriais)
## cargas fatoriais:  0.467903 0.475896 0.4562445 0.4531826 0.3755746

1.5.3 Construção de um Ranking

1.5.3.1 Scores Fatoriais para F1

Assumindo-se apenas o F1 como indicador

Observação: Na construção de rankings no R, devemos efetuar a multiplicação por -1, visto que os scores fatoriais das observações mais fortes são, por padrão, apresentados acompanhados do sinal de menos.

score_D1 <- scores_fatoriais[1,]

F1 <- t(apply(ENEM_std, 1, function(x) x * score_D1))

F1 <- data.frame(F1) %>%
  mutate(fator1 = rowSums(.) * 1)

1.5.3.2 Consolidando as tabelas

ENEM_notas["Fator1"] <- F1$fator1

1.5.3.3 Ranking

var_compartilhada <- (afpc_ENEM$sdev ^ 2/sum(afpc_ENEM$sdev ^ 2))

ENEM_notas %>%
  mutate(pontuacao = Fator1 * var_compartilhada[1]) -> ENEM_final

1.5.3.4 Visualizando o ranking final

visualizando apenas os 10 primeiros “classificados”

head(ENEM_final, n = 10L) %>%
  arrange(desc(pontuacao)) %>%
  kable() %>%
  kable_styling(bootstrap_options = "striped", 
                full_width = T, 
                font_size = 12)
NU_NOTA_CN NU_NOTA_CH NU_NOTA_LC NU_NOTA_MT NU_NOTA_REDACAO Fator1 pontuacao
200004191733 540.6 584.0 609.4 672.5 900 1.6497888 1.0669655
200004887669 586.5 650.9 568.3 639.0 800 1.6479832 1.0657978
200005950838 604.3 585.5 548.2 626.9 500 1.0360876 0.6700674
200006134766 498.3 518.9 485.6 396.8 560 -0.2224172 -0.1438435
200003899122 461.5 454.1 455.7 382.7 640 -0.5811558 -0.3758501
200001549389 475.4 494.4 463.6 333.5 520 -0.6540330 -0.4229818
200005805354 412.6 462.0 484.7 410.8 520 -0.7008762 -0.4532766
200005144676 364.0 468.2 470.2 470.1 560 -0.7079266 -0.4578364
200006161469 458.6 393.4 443.9 366.1 520 -1.0039128 -0.6492591
200004395365 392.9 340.2 387.4 335.0 440 -1.7642906 -1.1410171

1.6 Tempo de Execução

TOTAL_DL <- c(TOTAL_DL$msg, TOTAL_DL$toc - TOTAL_DL$tic)
TOTAL_DW <- c(TOTAL_DW$msg, TOTAL_DW$toc - TOTAL_DW$tic)
TOTAL_AF <- c(TOTAL_AF$msg, TOTAL_AF$toc - TOTAL_AF$tic)
TOTAL <- c(TOTAL$msg, TOTAL$toc - TOTAL$tic)

tempos <- data.frame(c(TOTAL_DL[1], TOTAL_DL[2]),
                     c(TOTAL_DW[1], TOTAL_DW[2]),
                     c(TOTAL_AF[1], TOTAL_AF[2]),
                     c(TOTAL[1], TOTAL[2]))

tempos %>%
  purrr::set_names(as.character(slice(., 1))) %>%
  slice(-1) -> tempos

data.frame(t(tempos)) -> tempos

tempos$elapsed <- as.numeric(tempos$elapsed)

tempos %>%
  kable() %>%
  kable_styling(bootstrap_options = "striped", 
                full_width = F, 
                font_size = 12)
elapsed
total_dataloading 1343.810
total_datawrangling 16.694
total_analisefatorial 16.533
total 1377.094